﻿using System;
using System.Collections.Generic;
using System.Linq;
using Internal.Runtime.Models;
using Runtime.Services.Battle;
using Runtime.Services.Battle.Entity;
using Runtime.Services.BattleAttack;
using Runtime.Services.BattleRecord;
using Runtime.Services.BattleSkill;
using UnityEngine;
using UnityEngine.Pool;

namespace Runtime.Models {

    /// <summary>
    /// 目标数据
    /// </summary>
    public interface IDFR_BattleAttackTargetModelBase : IDFR_Model, IDFR_BattleEntityModel {

        IDFR_BattleAttackTargetModelBaseSetter AsSetter();

        IDFR_BattleAttackTarget AsAttackTarget();

        IDFR_BattleBuffApplier AsBuffApplier();

        IDFR_BattleEffectTarget AsEffectTarget();

        IDFR_BattleDeathModel AsDeath();

        /// <summary>
        /// 是否已经死亡
        /// </summary>
        bool IsDead { get; }

        /// <summary>
        /// 生命值上限
        /// </summary>
        IDFR_ReadOnlyBattleData HPMax { get; }

        /// <summary>
        /// 当前生命值
        /// </summary>
        IDFR_ReadOnlyBattleData HP { get; }

        /// <summary>
        /// 防御
        /// </summary>
        IDFR_ReadOnlyBattleData Defense { get; }

        /// <summary>
        /// 闪避
        /// </summary>
        IDFR_ReadOnlyBattleData Dodge { get; }

        /// <summary>
        /// 移动速度
        /// </summary>
        IDFR_ReadOnlyBattleData MoveSpeed { get; }

        /// <summary>
        /// 地图位置
        /// </summary>
        DFR_BattleMapPosition MapPosition { get; }

        /// <summary>
        /// 是否是Boss
        /// </summary>
        bool IsBoss { get; }

        /// <summary>
        /// 是否是Boss或精英
        /// </summary>
        bool IsEliteOrBoss { get; }
    }

    public interface IDFR_BattleAttackTargetModelBaseSetter : IDFR_BattleAttackTargetModelBase {

        /// <summary>
        /// 生命值上限
        /// </summary>
        new IDFR_BattleComplexData HPMax { get; }

        /// <summary>
        /// 移动速度
        /// </summary>
        new IDFR_BattleComplexData MoveSpeed { get; }

        /// <summary>
        /// 防御
        /// </summary>
        new IDFR_BattleComplexData Defense { get; }

        /// <summary>
        /// 闪避
        /// </summary>
        new IDFR_BattleComplexData Dodge { get; }
    }

    public abstract class DFR_BattleAttackTargetModelBase : DFR_Model,
        IDFR_BattleAttackTargetModelBase, IDFR_BattleAttackTargetModelBaseSetter, IDFR_BattleAttackTargetModelBaseInternal,
        IDFR_BattleEntityModelInternal, IDFR_BattleDeathModel, IDFR_BattleMapPositionGetter,
        IDFR_BattleAttackTarget, IDFR_BattleAttackDefender, IDFR_BattleEffectTarget, IDFR_BattleBuffApplier {

        private sealed class BuffDamage : IDFR_BattleAttackDamage {

            public DFR_BattleAttackDamageType Type { get; init; }

            public F64 Value { get; init; }

            public F64 OriginValue { get; init; }
        }

        public IDFR_BattleAttackTargetModelBaseSetter AsSetter() => this;

        public IDFR_BattleAttackTarget AsAttackTarget() => this;

        public IDFR_BattleEffectTarget AsEffectTarget() => this;

        public IDFR_BattleBuffApplier AsBuffApplier() => this;

        public IDFR_BattleDeathModel AsDeath() => this;

        IDFR_BattleAttackDefender IDFR_BattleAttackTarget.AsAttackDefender() => this;

        public event IDFR_BattleAttackTarget.UnderattackDelegate Underattack;

        public DFR_BattleEntityInstanceID EntityInstanceID { get; private set; } = DFR_BattleEntityInstanceID.Empty;

        DFR_BattleEntityInstanceID IDFR_BattleDeathModel.EntityInstanceID => EntityInstanceID;

        DFR_BattleEntityInstanceID IDFR_BattleAttackTarget.EntityInstanceID => EntityInstanceID;

        IEnumerable<IDFR_BattleBuffProvider> IDFR_BattleBuffApplier.BuffProviders => m_BuffProviderSet;
        private HashSet<IDFR_BattleBuffProvider> m_BuffProviderSet = new();

        [Autowired]
        protected readonly IDFR_BattleComplexData m_HPMax;
        public IDFR_ReadOnlyBattleData HPMax => m_HPMax;
        F64 IDFR_BattleAttackDefender.HPMax => m_HPMax.Value;
        IDFR_BattleComplexData IDFR_BattleAttackTargetModelBaseSetter.HPMax => m_HPMax;

        [Autowired]
        protected readonly IDFR_BattleData m_HP;
        public IDFR_ReadOnlyBattleData HP => m_HP;
        F64 IDFR_BattleAttackDefender.HP => HP.Value;

        [Autowired]
        protected readonly IDFR_BattleComplexData m_MoveSpeed;
        public IDFR_ReadOnlyBattleData MoveSpeed => m_MoveSpeed;
        IDFR_BattleComplexData IDFR_BattleAttackTargetModelBaseSetter.MoveSpeed => m_MoveSpeed;
        F64 IDFR_BattleMapPositionProvider.MoveSpeed => m_MoveSpeed.Value;

        [Autowired]
        protected readonly IDFR_BattleComplexData m_Defense;
        public IDFR_ReadOnlyBattleData Defense => m_Defense;
        F64 IDFR_BattleAttackDefender.Defense => Defense.Value;
        IDFR_BattleComplexData IDFR_BattleAttackTargetModelBaseSetter.Defense => m_Defense;

        [Autowired]
        protected readonly IDFR_BattleComplexData m_Dodge;
        public IDFR_ReadOnlyBattleData Dodge => m_Dodge;
        F64 IDFR_BattleAttackDefender.Dodge => Dodge.Value;
        IDFR_BattleComplexData IDFR_BattleAttackTargetModelBaseSetter.Dodge => m_Dodge;

        DFR_BattleMapPosition IDFR_BattleMapPositionGetter.MapPosition => MapPosition;
        DFR_BattleMapPosition IDFR_BattleAttackTargetModelBase.MapPosition => MapPosition;
        DFR_BattleMapPosition IDFR_BattleMapPositionProvider.MapPosition => MapPosition;
        protected abstract DFR_BattleMapPosition MapPosition { get; }

        DFR_BattleMapPosition IDFR_BattleMapPositionProvider.LastMapPosition => LastMapPosition;
        protected abstract DFR_BattleMapPosition LastMapPosition { get; }

        public bool IsDead => IsDisposed || m_HP.Value <= F64.Zero;

        bool IDFR_BattleEffectTarget.IsEnabled => IsEnabled;
        bool IDFR_BattleMapPositionProvider.IsEnabled => IsEnabled;
        protected virtual bool IsEnabled => !IsDead;

        bool IDFR_BattleAttackTarget.IsBoss => IsBoss;
        public abstract bool IsBoss { get; }

        public bool IsEliteOrBoss => IsBoss;

        void IDFR_BattleMapPositionProvider.Dispose() { } // 不需要实现
        protected override void Dispose() {
            Underattack = null;
            EntityInstanceID = DFR_BattleEntityInstanceID.Empty;
            m_BuffProviderSet = null;
            base.Dispose();
        }

        protected abstract DFR_BattleMapPosition SupposeMove(F64 seconds);
        DFR_BattleMapPosition IDFR_BattleMapPositionProvider.SupposeMove(F64 seconds) {
            return SupposeMove(seconds);
        }

        protected abstract Vector2F64 RenderOffset { get; }
        Vector2F64 IDFR_BattleMapPositionProvider.RenderOffset => RenderOffset;

        protected abstract bool Initialize();

        void IDFR_BattleEntityModelInternal.Initialize(DFR_BattleEntityInstanceID instanceID) {
            EditBegin();
            EntityInstanceID = instanceID;
            EditDone();
        }

        void IDFR_BattleAttackTargetModelBaseInternal.Initialize() {
            if (Initialize()) {
            }
        }

        void IDFR_BattleBuffApplier.AddBuff(IDFR_BattleBuffProvider buffProvider) {
            m_BuffProviderSet.Add(buffProvider);

            m_MoveSpeed.Base.Add(buffProvider.MoveSpeedBase);
            m_MoveSpeed.Factor.Add(buffProvider.MoveSpeedFactor);
            m_MoveSpeed.Additional.Add(buffProvider.MoveSpeedAdditional);
            m_Defense.Base.Add(buffProvider.DefenseBase);
            m_Defense.Factor.Add(buffProvider.DefenseFactor);
            m_Defense.Additional.Add(buffProvider.DefenseAdditional);
            m_Dodge.Base.Add(buffProvider.DodgeBase);
            m_Dodge.Factor.Add(buffProvider.DodgeFactor);
            m_Dodge.Additional.Add(buffProvider.DodgeAdditional);

            if (buffProvider.DamageHPMaxAdditional?.Value > F64.Zero) {
                var damage = m_HPMax.Value * buffProvider.DamageHPMaxAdditional.Value;
                var origin = damage;
                if (damage > HP.Value) {
                    damage = HP.Value;
                }
                AsAttackTarget().DoUnderattack(new BuffDamage { Type = DFR_BattleAttackDamageType.Normal, OriginValue = origin, Value = damage }, out var killType);
                // TODO: 需要反馈击杀情况
            }
            if (buffProvider.DamageHPAdditional?.Value > F64.Zero) {
                var damage = m_HP.Value * buffProvider.DamageHPAdditional.Value;
                var origin = damage;
                if (damage > HP.Value) {
                    damage = HP.Value;
                }
                AsAttackTarget().DoUnderattack(new BuffDamage { Type = DFR_BattleAttackDamageType.Normal, OriginValue = origin, Value = damage }, out var killType);
                // TODO: 需要反馈击杀情况
            }
        }

        void IDFR_BattleBuffApplier.RemoveBuff(IDFR_BattleBuffProvider buffProvider) => RemoveBuff(buffProvider);
        private void RemoveBuff(IDFR_BattleBuffProvider buffProvider) {
            m_BuffProviderSet.Remove(buffProvider);
            m_MoveSpeed.Base.Remove(buffProvider.MoveSpeedBase);
            m_MoveSpeed.Factor.Remove(buffProvider.MoveSpeedFactor);
            m_MoveSpeed.Additional.Remove(buffProvider.MoveSpeedAdditional);
            m_Defense.Base.Remove(buffProvider.DefenseBase);
            m_Defense.Factor.Remove(buffProvider.DefenseFactor);
            m_Defense.Additional.Remove(buffProvider.DefenseAdditional);
            m_Dodge.Base.Remove(buffProvider.DodgeBase);
            m_Dodge.Factor.Remove(buffProvider.DodgeFactor);
            m_Dodge.Additional.Remove(buffProvider.DodgeAdditional);
        }

        void IDFR_BattleBuffApplier.RemoveBuff(DFR_BattleEntityID id, Action<IDFR_BattleBuffProvider> onRemove) {
            var removingSet = HashSetPool<IDFR_BattleBuffProvider>.Get();
            foreach (var buffProvider in m_BuffProviderSet) {
                if (buffProvider.EntityInstanceID.ID == id) {
                    removingSet.Add(buffProvider);
                }
            }
            foreach (var buffProvider in removingSet) {
                RemoveBuff(buffProvider);
                onRemove?.Invoke(buffProvider);
            }
            HashSetPool<IDFR_BattleBuffProvider>.Release(removingSet);
        }

        protected void RemoveAllBuff() {
            foreach (var buffProvider in m_BuffProviderSet.ToArray()) {
                BattleSkillServiceBase.Instance.RemoveBuff(EntityInstanceID, buffProvider);
            }
            BattleSkillServiceBase.Instance.ClearBuffInfluence(EntityInstanceID);
        }

        void IDFR_BattleBuffApplier.SyncBuffPositionOnce() {
            foreach (var buffProvider in m_BuffProviderSet) {
                if (buffProvider is IDFR_BattleEffectHolder effectHolder) {
                    effectHolder.AsSetter().SyncPositionOnce(EntityInstanceID);
                }
            }
        }

        protected abstract bool DoUnderattack(IDFR_BattleAttackDamage damage, out IDFR_BattleRecordService.KillType killType);
        bool IDFR_BattleAttackTarget.DoUnderattack(IDFR_BattleAttackDamage damage, out IDFR_BattleRecordService.KillType killType) {
            if (!IsEnabled) {
                killType = default;
                return false;
            }
            DoUnderattack(damage, out killType);
            Underattack?.Invoke(damage);
            if (IsDead) {
                RemoveAllBuff();
            }
            return true;
        }
    }
}

namespace Internal.Runtime.Models {

    public interface IDFR_BattleAttackTargetModelBaseInternal {

        void Initialize();
    }
}